Overview
In the previous two assignments, we obtained data associated with the study Cannabidiol inhibits SARS-CoV-2 replication through induction of the host ER stress and innate immune responses and conducted thresholded differential gene expression analysis. We obtained the dataset from GEO with ID GSE168797, associated with the study Cannabidiol inhibits SARS-COV-2 replication and promotes the host innate immune response published on Science Advances. Out of the total of 57832 genes, 13705 remained after removing low counts and genes with duplicate identifiers. The top terms associated with the upregulated genes returned from the thresholded analysis using g:profiler are response to endoplasmic reticulum stress, proteasomal protein catabolic process, ERAD (Endoplasmic-reticulum-associated protein degradation) pathway; the top terms associated with the downregulated genes are mitotic nuclear division, chromatin binding, cell cycle.
The authors hypothesized and concluded that cannabidiol inhibits SARS-CoV-2 replication by up-regulating the host IRE1α ribonuclease endoplasmic reticulum (ER) stress response and interferon signaling pathways.
In this assignment, we will further investigate differential gene expression and attempt to discover and learn more about the pathways involved in CBD’s suggested antiviral effect against SARS-CoV-2. In particular, we will use non-thresholded gene enrichment analysis to obtain a more diverse portfolio of differentially expressed genes. The results from non-thresholded analysis will also serve as comparison to the results from the previously done thresholded analysis. Ideally, the non-thresholded analysis results further strengthen the plausibility of our previous results and the authors’ hypothesis in the original publication. Using the results obtained from the non-thresholded analysis, we will create an enrichment map network and conduct further analysis using the network.
Import Packages
if (!requireNamespace("RCurl", quietly = TRUE))
install.packages("RCurl")
library("RCurl")
if (!requireNamespace("reshape2", quietly = TRUE))
install.package("reshape2")
if (!requireNamespace("RCy3", quietly = TRUE))
BiocManager::install("RCy3")
# high-res figures
knitr::opts_chunk$set(dpi=600,fig.width=7)
Helper functions for obtaining the GMT files and running GSEA.
fileExists_wildcard <- function(pattern, dir) {
# check if there is any file matching the pattern (regex)
return(length(grep(pattern, list.files(dir))) > 0)
}
folderExists_wildcard <- function(pattern, dir) {
# check if there is any file matching the pattern (regex)
return(length(grep(pattern, list.dirs(dir, recursive = FALSE))) > 0)
}
run_gsea <- function(gsea_jar, rnk, gmx, nperm, max_termsize, min_termsize, out_dir, rpt_label) {
command <- paste(
gsea_jar,
"GSEAPreRanked -gmx", gmx,
"-rnk", rnk,
"-nperm", nperm,
"-set_max", max_termsize,
"-set_min", min_termsize,
"-out", out_dir,
"-rpt_label", rpt_label,
"> gsea_out.txt",
sep = " ")
if (!folderExists_wildcard(rpt_label, "gsea_out"))
system(command)
else
print("GSEA results already exists; remove previous result or use a different job name to continue.")
}
getGMT <- function(src, pattern) {
gmt_url <- src
filenames = getURL(gmt_url)
textConn = textConnection(filenames)
contents = readLines(textConn)
close(textConn)
# filter out the filenames using the regex pattern
rx = gregexpr(pattern, contents,
perl = TRUE)
gmt_file <- unlist(regmatches(contents, rx))
# download the gmt file if there is no file with extension .gmt in the gmt folder
if (!fileExists_wildcard(".gmt", "gmt"))
download.file(paste(gmt_url, gmt_file, sep = ""), destfile = file.path(getwd(), "gmt", gmt_file))
}
Non-thresholded Gene Enrichment Analysis
Create Ranked List
To perform a non-thresholded gene enrichment analysis, we use GSEA. But before we do that, we first create a ranked list using the set of all differentially expressed genes obtained in Assignment 2.
diff_exp_lst
Recall that rank can be calculated using the following formula \[
\mathrm{rank} = \mathrm{sign}(\mathrm{logFC}) \cdot(-\log_{10}p)
\]
# calculate ranks
ranks <- sign(diff_exp_lst$logFC) * -log10(diff_exp_lst$PValue)
# store the ranks along with gene names
rank_list_gene_names <- diff_exp_lst$hgnc_symbol
rank_list <- cbind(rank_list_gene_names, ranks)
# sort the ranked list
rank_list <- rank_list[order(as.numeric(rank_list[,2]), decreasing = TRUE), ]
colnames(rank_list) <- c("GeneName", "rank")
# store the ranked list
write.table(rank_list, file.path(getwd(), "CBD_vs_Veh_ranks.rnk"),
col.names = TRUE, sep = "\t", row.names = FALSE, quote = FALSE)
kable(head(rank_list), caption = "Table 1: Top genes in the ranked list") %>% kableExtra::kable_styling("striped")
Table 1: Top genes in the ranked list
|
GeneName
|
rank
|
|
DNAJB9
|
12.93030398338
|
|
IGFBP1
|
12.7474872887814
|
|
HSPA5
|
12.4494138867865
|
|
CRELD2
|
11.7308461237434
|
|
ADGRF4
|
11.5485864149102
|
|
GABARAPL1
|
11.5327022737292
|
Download Gene Sets
For this analysis, we will use the gene sets available at Bader’s Lab
getGMT(
src = "http://download.baderlab.org/EM_Genesets/current_release/Human/symbol/",
pattern = "(?<=<a href=\")(.*.GOBP_AllPathways_no_GO_iea.*.)(.gmt)(?=\">)"
)
The gene set we used for this analysis is “Human_GOBP_AllPathways_no_GO_iea_April_01_2022_symbol.gmt” from Bader’s lab. The “no_GO_iea” tag in the file name indicates that the gene set does not include genes inferred from electronic annotation.
Analysis using GSEA
Next, we run GSEA from the command line. Note that the GSEA jar is stored at “GSEA_4.2.4/”. If you have the GSEA jar stored at a different location, change the gsea_jar parameter to point to the correct location.
## function that reports that GSEA does not exists and terminate the knitting of the current notebook
reportGseaDNE <- function() {
print("GSEA not found")
knitr::knit_exit()
}
# check if GSEA directory exists
if (folderExists_wildcard("GSEA_*", "~")) {
# get the GSEA installation (version independent)
gsea_dir = list.dirs("~", recursive = FALSE)[grep("GSEA_*", list.dirs("~", recursive = FALSE))]
if (length(gsea_dir) > 0) {
gsea_path = file.path(gsea_dir[1], "gsea-cli.sh")
# if the shell script exists, then execute GSEA command
if (file.exists(gsea_path)) {
run_gsea(
gsea_jar = gsea_path,
rnk = file.path(getwd(), "CBD_vs_Veh_ranks.rnk"),
gmx = file.path(getwd(), "gmt", "Human_GOBP_AllPathways_no_GO_iea_April_01_2022_symbol.gmt"),
nperm = 1000,
max_termsize = 200,
min_termsize = 15,
out_dir = file.path(getwd(), "gsea_out"),
rpt_label = "CBD_vs_Veh_GSEAAnalysis")
}
else
reportGseaDNE()
} else
reportGseaDNE()
} else {
reportGseaDNE()
}
After running the previous block successfully, we would have the GSEA result stored at the folder gsea_out/CBD_vs_Veh_VSEAAnalysis.GseaPreranked.xxx. We can pull the report for the positive and negative classes.
gsea_folder_names <- list.dirs("gsea_out", recursive = FALSE)[grepl("CBD_vs_Veh_GSEAAnalysis", list.dirs("gsea_out", recursive = FALSE))]
gsea_folder_name <- gsea_folder_names[1]
gsea_job_id <- tail(strsplit(gsea_folder_name, "\\.")[[1]], n = 1)
gsea_pos <- read.csv(file.path(gsea_folder_name, sprintf("gsea_report_for_na_pos_%s.tsv", gsea_job_id)), sep = "\t")
gsea_neg <- read.csv(file.path(gsea_folder_name, sprintf("gsea_report_for_na_neg_%s.tsv", gsea_job_id)), sep = "\t")
We would like to parse the rows in the GSEA report so that it is more readable.
# parse the NAME column in GSEA output (split by '%')
parseGseaName <- function(gsea_table) {
splitted_names = reshape2::colsplit(gsea_table$NAME, '%', names = c("description", 'src', 'id'))
return(cbind(gsea_table, splitted_names))
}
gsea_pos <- parseGseaName(gsea_pos)
gsea_neg <- parseGseaName(gsea_neg)
kable(head(gsea_pos[,c("description", "src", "SIZE", "NES", "ES")]), caption = "Table 2: Top terms of upregualted genes") %>% kableExtra::kable_styling("striped")
Table 2: Top terms of upregualted genes
|
description
|
src
|
SIZE
|
NES
|
ES
|
|
RESPONSE TO ENDOPLASMIC RETICULUM STRESS
|
GOBP
|
85
|
3.725632
|
0.5870175
|
|
UNFOLDED PROTEIN RESPONSE (UPR)
|
REACTOME
|
44
|
3.523760
|
0.6604784
|
|
IRE1ALPHA ACTIVATES CHAPERONES
|
REACTOME
|
27
|
3.277616
|
0.6968865
|
|
ASPARAGINE N-LINKED GLYCOSYLATION
|
REACTOME
|
104
|
3.171751
|
0.4745622
|
|
ERAD PATHWAY
|
GOBP
|
48
|
3.165996
|
0.5732202
|
|
XBP1(S) ACTIVATES CHAPERONE GENES
|
REACTOME
|
26
|
3.146467
|
0.6926015
|
kable(head(gsea_neg[,c("description", "src", "SIZE", "NES", "ES")]), caption = "Table 3: Top terms of downregulated genes") %>% kableExtra::kable_styling("striped")
Table 3: Top terms of downregulated genes
|
description
|
src
|
SIZE
|
NES
|
ES
|
|
NUCLEAR CHROMOSOME SEGREGATION
|
GOBP
|
76
|
-5.127148
|
-0.7340092
|
|
CHROMOSOME SEGREGATION
|
GOBP
|
89
|
-5.023200
|
-0.6817771
|
|
SISTER CHROMATID SEGREGATION
|
GOBP
|
66
|
-4.972249
|
-0.7265686
|
|
MITOTIC CELL CYCLE PROCESS
|
GOBP
|
186
|
-4.693581
|
-0.5358869
|
|
NUCLEAR DIVISION
|
GOBP
|
92
|
-4.636481
|
-0.6301082
|
|
MITOTIC SISTER CHROMATID SEGREGATION
|
GOBP
|
60
|
-4.625700
|
-0.7114142
|
We also present the enrichment plots for some of the top terms associated with the upregulated genes.
The top terms associated with the upregulated genes are all related to ER stress response and more interestingly, unfolded protein response. In particular, ERAD (ER assocaited protein degradation) pathway is also one of the top terms. Those pathways and mechanisms are also discussed in the literature. We will explore those pathway using network analysis in the next section.
Discussion
For this analysis, I used GSEA version 4.2.3. I used the GSEA preranked analysis in GSEA. The geneset used was obtained from Bader’s lab’s repository. The code for obtaining the geneset is shown above. The geneset is created on April 1, 2022. The geneset is curated from GO, GOBP, MSigdb, Reactome, WikiPathways, NetPath, Panther, and HumanCyc.
In the enrichment result, the positive phenotype are the samples treated with CBD, and the negative phenotype are the ones without CBD treatment. 1064 / 2059 gene sets are upregulated in the positive samples, and 995 / 2059 gene sets are upregulated in the negative samples. In the positive phenotype, 217 gene sets are significantly enriched at nominal pvalue < 1%; in the negative phenotype, 342 gene sets are significantly enriched at nominal pvalue < 1%. The top terms associated with the positive samples are: RESPONSE TO ENDOPLASMIC RETICULUM STRESS (GO), UNFOLDED PROTEIN RESPONSE (UPR) (Reactome), IRE1ALPHA ACTIVATES CHAPERONES (Reactome). The top terms associated with the negative samples are: NUCLEAR CHROMOSOME SEGREGATION, CHROMOSOME SEGREGATION, SISTER CHROMATID SEGREGATION, all from GOBP.
The results from non-thresholded analysis using GSEA is very similar to the result obtained from the previous analysis using G:profiler. The upregulated genes are mostly related to ER stress response and protein degradation whereas the donwregulated genes are mostly related to cell cycle regulation and cell divisions. However, overall, the terms from the results using GSEA is more diverse. This is because GSEA is not a thresholded method and it gets to consider all genes instead of just those passed the threshold in thresholded methods. Although the top terms are mostly the same, this is not a straightforward comparison because the two methods (GSEA v.s. G:profiler) uses different approaches. The similarity in the the top terms is likely attributed to the significant overrepresentation of certain genes. This also gives us strong evidence to believe that the differentially expressed genes are more likely than not to be involved in these pathways.
Analysis of UPR Pathway
We further investigate the unfolded protein response pathway. The pathway is of particular interest because the authors proposed this as the potential mechanism for the antiviral effect of CBD. This pathway is available on Reactome. Here is a detailed pathway diagram obtained from Reactome.
Export the normalized count file (with HGNC symbol annotation) for annotation on Reactome pathway diagram.
write.csv(normalized_counts_annot[3:14], file = "normalized_count_annotated.txt")
write.csv(qlf_diff_exp$table, file = "qlf_diff_exp.txt")
The expression data is uploaded to the online analysis tools provided by Reactome. Below is the resulting pathway diagram with the genes in the pathway colored based on their level of differential expression (log FC). As shown in the figure, the majority of genes in this pathway are upregulated although a handful are also downregulated. Unfortunately, the built-in tool in Reactome does not allow us to annotate the pathway with p-value or the acutal numerial logFC value.
We repeat a similar analysis using Cytoscape. This time, we use the expression data obtained in A2. This file includes not only the logFC but also the p-values for each differentially expressed gene. After importing the Reactome pathway into Cytoscape, we write an automation script to annotate the network using logFC and p-values:
nodes <- RCy3::getAllNodes()
attrib_table <- RCy3::getTableColumns()
for (n in nodes) {
npos = RCy3::getNodePosition(node.names = n)
attrib = attrib_table[attrib_table$name == n,]
if (!is.null(attrib$logFC)) {
RCy3::addAnnotationText(text = sprintf("logFC = %.2f", attrib$logFC), x.pos = npos$x_location, y.pos = npos$y_location)
RCy3::addAnnotationText(text = sprintf("p = %.2g", attrib$PValue), x.pos = npos$x_location, y.pos = npos$y_location + 12)
}
}
This script was run outside the notebook. It is shown here for demonstration purpose only.
The final annoated network is annoted with logFC and p-values. The color of each node corresponds to log fold change (red = upregulated, blue = downregulated) and the size of each node is inverse proportional to the p-value of the gene represented by the node.
As shown in the figure above, we can see the genes involved in the unfolded protein response pathway are mostly significantly upregulated. This is consistent with the finding in the original publication. The authors further confirmed this by observing the effect on SARS-CoV-2 infection in cells with the ERN1 gene (one of the gene involved in this pathway) knocked out. Their experiment shows reduced antiviral effects even with CBD treatment in ERN1 knockout cells.
Reference
Isserlin, R. (n.d.). Enrichment Map Analysis Pipeline. Bader Lab GitHub.
Kucera, M., Isserlin, R., Arkhangorodsky, A., & Bader, G. D. (2016). AutoAnnotate: A Cytoscape app for summarizing networks with Semantic Annotations. F1000Research, 5, 1717. https://doi.org/10.12688/f1000research.9090.1
Reimand, J., Isserlin, R., Voisin, V., Kucera, M., Tannus-Lopes, C., Rostamianfar, A., Wadi, L., Meyer, M., Wong, J., Xu, C., Merico, D., & Bader, G. D. (2019). Pathway enrichment analysis and visualization of OMICS data using G:Profiler, GSEA, Cytoscape and EnrichmentMap. Nature Protocols, 14(2), 482–517. https://doi.org/10.1038/s41596-018-0103-9
Chen Y, Lun ATL, Smyth GK (2016). From reads to genes to pathways: differential expression analysis of RNA-Seq experiments using Rsubread and the edgeR quasi-likelihood pipeline. F1000Research 5, 1438
Durinck, S., Spellman, P. T., Birney, E., & Huber, W. (2009). Mapping identifiers for the integration of genomic datasets with the R/Bioconductor package biomaRt. Nature - protocols, 4(8), 1184–1191. https://doi.org/10.1038/nprot.2009.97 Martin Morgan (2021). BiocManager: Access the Bioconductor Project Package Repository. R package version 1.30.16. https://CRAN.R-project.org/package=BiocManager
McCarthy DJ, Chen Y and Smyth GK (2012). Differential expression analysis of multifactor RNA-Seq experiments with respect to biological variation. Nucleic Acids Research 40, 4288-4297
Nguyen, L. C., Yang, D., Nicolaescu, V., Best, T. J., Ohtsuki, T., Chen, S.-N., Friesen, J. B., Drayman, N., Mohamed, A., Dann, C., Silva, D., Gula, H., Jones, K. A., Millis, J. M., Dickinson, B. C., Tay, S., Oakes, S. A., Pauli, G. F., Meltzer, D. O., … Rosner, M. R. (2021). Cannabidiol inhibits SARS-COV-2 replication and promotes the host innate immune response. Science Advances. https://www.science.org/doi/abs/10.1126/sciadv.abi6110 Robinson MD, McCarthy DJ and Smyth GK (2010). edgeR: a Bioconductor package for differential expression analysis of digital gene expression data. Bioinformatics 26, 139-140
Gu, Z. (2016) Complex heatmaps reveal patterns and correlations in multidimensional genomic data. Bioinformatics.
Kolberg L, Raudvere U, Kuzmin I, Vilo J, Peterson H (2020). “gprofiler2- an R package for gene list functional enrichment analysis and namespace conversion toolset g:Profiler.” F1000Research, 9 (ELIXIR)(709). R package version 0.2.1.
Stefan Milton Bache and Hadley Wickham (2020). magrittr: A Forward-Pipe Operator for R. https://magrittr.tidyverse.org, https://github.com/tidyverse/magrittr. van Breemen, R. B., Muchiri, R. N., Bates, T. A., Weinstein, J. B., Leier, H. C., Farley, S., & Tafesse, F. G. (2022).
Cannabinoids Block Cellular Entry of SARS-CoV-2 and the Emerging Variants. Journal of natural products, 85(1), 176–184. https://doi.org/10.1021/acs.jnatprod.1c00946
Fabregat A, Sidiropoulos K, Viteri G, Marin-Garcia P, Ping P, Stein L, D’Eustachio P, Hermjakob H. Reactome diagram viewer: data structures and strategies to boost performance. Bioinformatics (Oxford, England). 2018 Apr;34(7) 1208-1214. doi: 10.1093/bioinformatics/btx752. PubMed PMID: 29186351. PubMed Central PMCID: PMC6030826.
Eizirik, D. L., Cardozo, A. K., & Cnop, M. (2008). The role for endoplasmic reticulum stress in diabetes mellitus. Endocrine reviews, 29(1), 42–61. https://doi.org/10.1210/er.2007-0015
Credle, J. J., Finer-Moore, J. S., Papa, F. R., Stroud, R. M., & Walter, P. (2005). On the mechanism of sensing unfolded protein in the endoplasmic reticulum. Proceedings of the National Academy of Sciences of the United States of America, 102(52), 18773–18784. https://doi.org/10.1073/pnas.0509487102
LS0tCnRpdGxlOiAiS2V2aW4gR2FvIC0gQXNzaWdubWVudCAzOiBEYXRhc2V0IFBhdGh3YXkgYW5kIE5ldHdvcmsgQW5hbHlzaXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBtYXRoamF4OiAiaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbWF0aGpheC8yLjcuNy9NYXRoSmF4LmpzP2NvbmZpZz1UZVgtTU1MLUFNX0NIVE1MIgotLS0KCiMgT3ZlcnZpZXcKCmBgYHtyIGEyX3NvdXJjZSwgaW5jbHVkZT1GQUxTRSxlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpvcHRpb25zKHdhcm49LTEpCmEyX291dHB1dCA8LSBrbml0cjo6a25pdF9jaGlsZCgnYXNzaWdubWVudDIuUm1kJywgcXVpZXQgPSBUUlVFKQojIHJ1biB0aGUgZ2FyYmFnZSBjb2xsZWN0b3IKZ2MoKQpgYGAKCkluIHRoZSBwcmV2aW91cyB0d28gYXNzaWdubWVudHMsIHdlIG9idGFpbmVkIGRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdHVkeSAqKkNhbm5hYmlkaW9sIGluaGliaXRzIFNBUlMtQ29WLTIgcmVwbGljYXRpb24gdGhyb3VnaCBpbmR1Y3Rpb24gb2YgdGhlIGhvc3QgRVIgc3RyZXNzIGFuZCBpbm5hdGUgaW1tdW5lIHJlc3BvbnNlcyoqIGFuZCBjb25kdWN0ZWQgdGhyZXNob2xkZWQgZGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcy4gV2Ugb2J0YWluZWQgdGhlIGRhdGFzZXQgZnJvbSBHRU8gd2l0aCBJRCBHU0UxNjg3OTcsIGFzc29jaWF0ZWQgd2l0aCB0aGUgc3R1ZHkgQ2FubmFiaWRpb2wgaW5oaWJpdHMgU0FSUy1DT1YtMiByZXBsaWNhdGlvbiBhbmQgcHJvbW90ZXMgdGhlIGhvc3QgaW5uYXRlIGltbXVuZSByZXNwb25zZSBwdWJsaXNoZWQgb24gU2NpZW5jZSBBZHZhbmNlcy4gT3V0IG9mIHRoZSB0b3RhbCBvZiA1NzgzMiBnZW5lcywgMTM3MDUgcmVtYWluZWQgYWZ0ZXIgcmVtb3ZpbmcgbG93IGNvdW50cyBhbmQgZ2VuZXMgd2l0aCBkdXBsaWNhdGUgaWRlbnRpZmllcnMuIFRoZSB0b3AgdGVybXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB1cHJlZ3VsYXRlZCBnZW5lcyByZXR1cm5lZCBmcm9tIHRoZSB0aHJlc2hvbGRlZCBhbmFseXNpcyB1c2luZyBnOnByb2ZpbGVyIGFyZSByZXNwb25zZSB0byBlbmRvcGxhc21pYyByZXRpY3VsdW0gc3RyZXNzLCBwcm90ZWFzb21hbCBwcm90ZWluIGNhdGFib2xpYyBwcm9jZXNzLCBFUkFEIChFbmRvcGxhc21pYy1yZXRpY3VsdW0tYXNzb2NpYXRlZCBwcm90ZWluIGRlZ3JhZGF0aW9uKSBwYXRod2F5OyB0aGUgdG9wIHRlcm1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgZG93bnJlZ3VsYXRlZCBnZW5lcyBhcmUgbWl0b3RpYyBudWNsZWFyIGRpdmlzaW9uLCBjaHJvbWF0aW4gYmluZGluZywgY2VsbCBjeWNsZS4KClRoZSBhdXRob3JzIGh5cG90aGVzaXplZCBhbmQgY29uY2x1ZGVkIHRoYXQgY2FubmFiaWRpb2wgaW5oaWJpdHMgU0FSUy1Db1YtMiByZXBsaWNhdGlvbiBieSB1cC1yZWd1bGF0aW5nIHRoZSBob3N0IElSRTHOsSByaWJvbnVjbGVhc2UgZW5kb3BsYXNtaWMgcmV0aWN1bHVtIChFUikgc3RyZXNzIHJlc3BvbnNlIGFuZCBpbnRlcmZlcm9uIHNpZ25hbGluZyBwYXRod2F5cy4KCkluIHRoaXMgYXNzaWdubWVudCwgd2Ugd2lsbCBmdXJ0aGVyIGludmVzdGlnYXRlIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5kIGF0dGVtcHQgdG8gZGlzY292ZXIgYW5kIGxlYXJuIG1vcmUgYWJvdXQgdGhlIHBhdGh3YXlzIGludm9sdmVkIGluIENCRCdzIHN1Z2dlc3RlZCBhbnRpdmlyYWwgZWZmZWN0IGFnYWluc3QgU0FSUy1Db1YtMi4gSW4gcGFydGljdWxhciwgd2Ugd2lsbCB1c2Ugbm9uLXRocmVzaG9sZGVkIGdlbmUgZW5yaWNobWVudCBhbmFseXNpcyB0byBvYnRhaW4gYSBtb3JlIGRpdmVyc2UgcG9ydGZvbGlvIG9mIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcy4gVGhlIHJlc3VsdHMgZnJvbSBub24tdGhyZXNob2xkZWQgYW5hbHlzaXMgd2lsbCBhbHNvIHNlcnZlIGFzIGNvbXBhcmlzb24gdG8gdGhlIHJlc3VsdHMgZnJvbSB0aGUgcHJldmlvdXNseSBkb25lIHRocmVzaG9sZGVkIGFuYWx5c2lzLiBJZGVhbGx5LCB0aGUgbm9uLXRocmVzaG9sZGVkIGFuYWx5c2lzIHJlc3VsdHMgZnVydGhlciBzdHJlbmd0aGVuIHRoZSBwbGF1c2liaWxpdHkgb2Ygb3VyIHByZXZpb3VzIHJlc3VsdHMgYW5kIHRoZSBhdXRob3JzJyBoeXBvdGhlc2lzIGluIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gVXNpbmcgdGhlIHJlc3VsdHMgb2J0YWluZWQgZnJvbSB0aGUgbm9uLXRocmVzaG9sZGVkIGFuYWx5c2lzLCB3ZSB3aWxsIGNyZWF0ZSBhbiBlbnJpY2htZW50IG1hcCBuZXR3b3JrIGFuZCBjb25kdWN0IGZ1cnRoZXIgYW5hbHlzaXMgdXNpbmcgdGhlIG5ldHdvcmsuCgojIyBJbXBvcnQgUGFja2FnZXMKCmBgYHtyIGEzX2ltcG9ydH0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJSQ3VybCIsIHF1aWV0bHkgPSBUUlVFKSkKICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpCmxpYnJhcnkoIlJDdXJsIikKCmlmICghcmVxdWlyZU5hbWVzcGFjZSgicmVzaGFwZTIiLCBxdWlldGx5ID0gVFJVRSkpCiAgaW5zdGFsbC5wYWNrYWdlKCJyZXNoYXBlMiIpCgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIlJDeTMiLCBxdWlldGx5ID0gVFJVRSkpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoIlJDeTMiKQoKIyBoaWdoLXJlcyBmaWd1cmVzCmtuaXRyOjpvcHRzX2NodW5rJHNldChkcGk9NjAwLGZpZy53aWR0aD03KQpgYGAKCkhlbHBlciBmdW5jdGlvbnMgZm9yIG9idGFpbmluZyB0aGUgR01UIGZpbGVzIGFuZCBydW5uaW5nIEdTRUEuCgpgYGB7ciBmaWxlX2hlbHBlcn0KZmlsZUV4aXN0c193aWxkY2FyZCA8LSBmdW5jdGlvbihwYXR0ZXJuLCBkaXIpIHsKICAjIGNoZWNrIGlmIHRoZXJlIGlzIGFueSBmaWxlIG1hdGNoaW5nIHRoZSBwYXR0ZXJuIChyZWdleCkKICByZXR1cm4obGVuZ3RoKGdyZXAocGF0dGVybiwgbGlzdC5maWxlcyhkaXIpKSkgPiAwKQp9Cgpmb2xkZXJFeGlzdHNfd2lsZGNhcmQgPC0gZnVuY3Rpb24ocGF0dGVybiwgZGlyKSB7CiAgIyBjaGVjayBpZiB0aGVyZSBpcyBhbnkgZmlsZSBtYXRjaGluZyB0aGUgcGF0dGVybiAocmVnZXgpCiAgcmV0dXJuKGxlbmd0aChncmVwKHBhdHRlcm4sIGxpc3QuZGlycyhkaXIsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkpID4gMCkKfQpgYGAKCmBgYHtyIGdzZWFfY21kfQpydW5fZ3NlYSA8LSBmdW5jdGlvbihnc2VhX2phciwgcm5rLCBnbXgsIG5wZXJtLCBtYXhfdGVybXNpemUsIG1pbl90ZXJtc2l6ZSwgb3V0X2RpciwgcnB0X2xhYmVsKSB7CiAgY29tbWFuZCA8LSBwYXN0ZSgKICAgIGdzZWFfamFyLCAKICAgICJHU0VBUHJlUmFua2VkIC1nbXgiLCBnbXgsIAogICAgIi1ybmsiLCBybmssIAogICAgIi1ucGVybSIsIG5wZXJtLCAKICAgICItc2V0X21heCIsIG1heF90ZXJtc2l6ZSwgCiAgICAiLXNldF9taW4iLCBtaW5fdGVybXNpemUsIAogICAgIi1vdXQiLCBvdXRfZGlyLAogICAgIi1ycHRfbGFiZWwiLCBycHRfbGFiZWwsCiAgICAiPiBnc2VhX291dC50eHQiLAogICAgc2VwID0gIiAiKQogIGlmICghZm9sZGVyRXhpc3RzX3dpbGRjYXJkKHJwdF9sYWJlbCwgImdzZWFfb3V0IikpCiAgICBzeXN0ZW0oY29tbWFuZCkKICBlbHNlCiAgICBwcmludCgiR1NFQSByZXN1bHRzIGFscmVhZHkgZXhpc3RzOyByZW1vdmUgcHJldmlvdXMgcmVzdWx0IG9yIHVzZSBhIGRpZmZlcmVudCBqb2IgbmFtZSB0byBjb250aW51ZS4iKQp9CmBgYAoKYGBge3IgZ2V0X2dtdF9oZWxwZXJ9CmdldEdNVCA8LSBmdW5jdGlvbihzcmMsIHBhdHRlcm4pIHsKICBnbXRfdXJsIDwtIHNyYwoKICBmaWxlbmFtZXMgPSBnZXRVUkwoZ210X3VybCkKICB0ZXh0Q29ubiA9IHRleHRDb25uZWN0aW9uKGZpbGVuYW1lcykKICBjb250ZW50cyA9IHJlYWRMaW5lcyh0ZXh0Q29ubikKICBjbG9zZSh0ZXh0Q29ubikKICAKICAjIGZpbHRlciBvdXQgdGhlIGZpbGVuYW1lcyB1c2luZyB0aGUgcmVnZXggcGF0dGVybgogIHJ4ID0gZ3JlZ2V4cHIocGF0dGVybiwgY29udGVudHMsCiAgICAgICAgICAgICAgICBwZXJsID0gVFJVRSkKICAKICBnbXRfZmlsZSA8LSB1bmxpc3QocmVnbWF0Y2hlcyhjb250ZW50cywgcngpKQogIAogICMgZG93bmxvYWQgdGhlIGdtdCBmaWxlIGlmIHRoZXJlIGlzIG5vIGZpbGUgd2l0aCBleHRlbnNpb24gLmdtdCBpbiB0aGUgZ210IGZvbGRlcgogIGlmICghZmlsZUV4aXN0c193aWxkY2FyZCgiLmdtdCIsICJnbXQiKSkKICAgIGRvd25sb2FkLmZpbGUocGFzdGUoZ210X3VybCwgZ210X2ZpbGUsIHNlcCA9ICIiKSwgZGVzdGZpbGUgPSBmaWxlLnBhdGgoZ2V0d2QoKSwgImdtdCIsIGdtdF9maWxlKSkKfQpgYGAKCiMgTm9uLXRocmVzaG9sZGVkIEdlbmUgRW5yaWNobWVudCBBbmFseXNpcwoKIyMgQ3JlYXRlIFJhbmtlZCBMaXN0CgpUbyBwZXJmb3JtIGEgbm9uLXRocmVzaG9sZGVkIGdlbmUgZW5yaWNobWVudCBhbmFseXNpcywgd2UgdXNlIEdTRUEuIEJ1dCBiZWZvcmUgd2UgZG8gdGhhdCwgd2UgZmlyc3QgY3JlYXRlIGEgcmFua2VkIGxpc3QgdXNpbmcgdGhlIHNldCBvZiBhbGwgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIG9idGFpbmVkIGluIEFzc2lnbm1lbnQgMi4KCmBgYHtyIHJhbmtlZF9saXN0X2Rpc3BsYXlfb3JpZ2luYWx9CmRpZmZfZXhwX2xzdApgYGAKClJlY2FsbCB0aGF0IHJhbmsgY2FuIGJlIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIGZvbGxvd2luZyBmb3JtdWxhCiQkClxtYXRocm17cmFua30gPSBcbWF0aHJte3NpZ259KFxtYXRocm17bG9nRkN9KSBcY2RvdCgtXGxvZ197MTB9cCkKJCQKCmBgYHtyIHJhbmtlZF9saXN0X2NyZWF0ZX0KIyBjYWxjdWxhdGUgcmFua3MKcmFua3MgPC0gc2lnbihkaWZmX2V4cF9sc3QkbG9nRkMpICogLWxvZzEwKGRpZmZfZXhwX2xzdCRQVmFsdWUpCgojIHN0b3JlIHRoZSByYW5rcyBhbG9uZyB3aXRoIGdlbmUgbmFtZXMKcmFua19saXN0X2dlbmVfbmFtZXMgPC0gZGlmZl9leHBfbHN0JGhnbmNfc3ltYm9sCnJhbmtfbGlzdCA8LSBjYmluZChyYW5rX2xpc3RfZ2VuZV9uYW1lcywgcmFua3MpCgojIHNvcnQgdGhlIHJhbmtlZCBsaXN0CnJhbmtfbGlzdCA8LSByYW5rX2xpc3Rbb3JkZXIoYXMubnVtZXJpYyhyYW5rX2xpc3RbLDJdKSwgZGVjcmVhc2luZyA9IFRSVUUpLCBdCmNvbG5hbWVzKHJhbmtfbGlzdCkgPC0gYygiR2VuZU5hbWUiLCAicmFuayIpCgojIHN0b3JlIHRoZSByYW5rZWQgbGlzdAp3cml0ZS50YWJsZShyYW5rX2xpc3QsIGZpbGUucGF0aChnZXR3ZCgpLCAiQ0JEX3ZzX1ZlaF9yYW5rcy5ybmsiKSwKICAgICAgICAgICAgY29sLm5hbWVzID0gVFJVRSwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCgprYWJsZShoZWFkKHJhbmtfbGlzdCksIGNhcHRpb24gPSAiVGFibGUgMTogVG9wIGdlbmVzIGluIHRoZSByYW5rZWQgbGlzdCIpICU+JSBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikKYGBgCgojIyBEb3dubG9hZCBHZW5lIFNldHMKCkZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIHVzZSB0aGUgZ2VuZSBzZXRzIGF2YWlsYWJsZSBhdCBCYWRlcidzIExhYgoKYGBge3IgZ2V0X2dtdH0KZ2V0R01UKAogIHNyYyA9ICJodHRwOi8vZG93bmxvYWQuYmFkZXJsYWIub3JnL0VNX0dlbmVzZXRzL2N1cnJlbnRfcmVsZWFzZS9IdW1hbi9zeW1ib2wvIiwKICBwYXR0ZXJuID0gIig/PD08YSBocmVmPVwiKSguKi5HT0JQX0FsbFBhdGh3YXlzX25vX0dPX2llYS4qLikoLmdtdCkoPz1cIj4pIgopCmBgYAoKVGhlIGdlbmUgc2V0IHdlIHVzZWQgZm9yIHRoaXMgYW5hbHlzaXMgaXMgIkh1bWFuX0dPQlBfQWxsUGF0aHdheXNfbm9fR09faWVhX0FwcmlsXzAxXzIwMjJfc3ltYm9sLmdtdCIgZnJvbSBCYWRlcidzIGxhYi4gVGhlICJub19HT19pZWEiIHRhZyBpbiB0aGUgZmlsZSBuYW1lIGluZGljYXRlcyB0aGF0IHRoZSBnZW5lIHNldCBkb2VzIG5vdCBpbmNsdWRlIGdlbmVzIGluZmVycmVkIGZyb20gZWxlY3Ryb25pYyBhbm5vdGF0aW9uLgoKIyMgQW5hbHlzaXMgdXNpbmcgR1NFQQoKTmV4dCwgd2UgcnVuIEdTRUEgZnJvbSB0aGUgY29tbWFuZCBsaW5lLiBOb3RlIHRoYXQgdGhlIEdTRUEgamFyIGlzIHN0b3JlZCBhdCAiR1NFQV80LjIuNC8iLiBJZiB5b3UgaGF2ZSB0aGUgR1NFQSBqYXIgc3RvcmVkIGF0IGEgZGlmZmVyZW50IGxvY2F0aW9uLCBjaGFuZ2UgdGhlIGBnc2VhX2phcmAgcGFyYW1ldGVyIHRvIHBvaW50IHRvIHRoZSBjb3JyZWN0IGxvY2F0aW9uLgoKYGBge3IgcnVuX2dzZWF9CiMjIGZ1bmN0aW9uIHRoYXQgcmVwb3J0cyB0aGF0IEdTRUEgZG9lcyBub3QgZXhpc3RzIGFuZCB0ZXJtaW5hdGUgdGhlIGtuaXR0aW5nIG9mIHRoZSBjdXJyZW50IG5vdGVib29rCnJlcG9ydEdzZWFETkUgPC0gZnVuY3Rpb24oKSB7CiAgcHJpbnQoIkdTRUEgbm90IGZvdW5kIikKICBrbml0cjo6a25pdF9leGl0KCkKfQojIGNoZWNrIGlmIEdTRUEgZGlyZWN0b3J5IGV4aXN0cwppZiAoZm9sZGVyRXhpc3RzX3dpbGRjYXJkKCJHU0VBXyoiLCAifiIpKSB7CiAgIyBnZXQgdGhlIEdTRUEgaW5zdGFsbGF0aW9uICh2ZXJzaW9uIGluZGVwZW5kZW50KQogIGdzZWFfZGlyID0gbGlzdC5kaXJzKCJ+IiwgcmVjdXJzaXZlID0gRkFMU0UpW2dyZXAoIkdTRUFfKiIsIGxpc3QuZGlycygifiIsIHJlY3Vyc2l2ZSA9IEZBTFNFKSldCiAgaWYgKGxlbmd0aChnc2VhX2RpcikgPiAwKSB7CiAgICBnc2VhX3BhdGggPSBmaWxlLnBhdGgoZ3NlYV9kaXJbMV0sICJnc2VhLWNsaS5zaCIpCiAgICAjIGlmIHRoZSBzaGVsbCBzY3JpcHQgZXhpc3RzLCB0aGVuIGV4ZWN1dGUgR1NFQSBjb21tYW5kCiAgICBpZiAoZmlsZS5leGlzdHMoZ3NlYV9wYXRoKSkgewogICAgICBydW5fZ3NlYSgKICAgICAgICBnc2VhX2phciA9IGdzZWFfcGF0aCwKICAgICAgICBybmsgPSBmaWxlLnBhdGgoZ2V0d2QoKSwgIkNCRF92c19WZWhfcmFua3Mucm5rIiksCiAgICAgICAgZ214ID0gZmlsZS5wYXRoKGdldHdkKCksICJnbXQiLCAiSHVtYW5fR09CUF9BbGxQYXRod2F5c19ub19HT19pZWFfQXByaWxfMDFfMjAyMl9zeW1ib2wuZ210IiksCiAgICAgICAgbnBlcm0gPSAxMDAwLAogICAgICAgIG1heF90ZXJtc2l6ZSA9IDIwMCwKICAgICAgICBtaW5fdGVybXNpemUgPSAxNSwKICAgICAgICBvdXRfZGlyID0gZmlsZS5wYXRoKGdldHdkKCksICJnc2VhX291dCIpLAogICAgICAgIHJwdF9sYWJlbCA9ICJDQkRfdnNfVmVoX0dTRUFBbmFseXNpcyIpCiAgICB9CiAgICBlbHNlCiAgICAgIHJlcG9ydEdzZWFETkUoKQogIH0gZWxzZQogICAgcmVwb3J0R3NlYURORSgpCiAgCn0gZWxzZSB7CiAgcmVwb3J0R3NlYURORSgpCn0KYGBgCgpBZnRlciBydW5uaW5nIHRoZSBwcmV2aW91cyBibG9jayBzdWNjZXNzZnVsbHksIHdlIHdvdWxkIGhhdmUgdGhlIEdTRUEgcmVzdWx0IHN0b3JlZCBhdCB0aGUgZm9sZGVyIGBnc2VhX291dC9DQkRfdnNfVmVoX1ZTRUFBbmFseXNpcy5Hc2VhUHJlcmFua2VkLnh4eGAuIFdlIGNhbiBwdWxsIHRoZSByZXBvcnQgZm9yIHRoZSBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgY2xhc3Nlcy4KCmBgYHtyIGdldF9nc2VhX3Jlc3VsdH0KZ3NlYV9mb2xkZXJfbmFtZXMgPC0gbGlzdC5kaXJzKCJnc2VhX291dCIsIHJlY3Vyc2l2ZSA9IEZBTFNFKVtncmVwbCgiQ0JEX3ZzX1ZlaF9HU0VBQW5hbHlzaXMiLCBsaXN0LmRpcnMoImdzZWFfb3V0IiwgcmVjdXJzaXZlID0gRkFMU0UpKV0KZ3NlYV9mb2xkZXJfbmFtZSA8LSBnc2VhX2ZvbGRlcl9uYW1lc1sxXQpnc2VhX2pvYl9pZCA8LSB0YWlsKHN0cnNwbGl0KGdzZWFfZm9sZGVyX25hbWUsICJcXC4iKVtbMV1dLCBuID0gMSkKCmdzZWFfcG9zIDwtIHJlYWQuY3N2KGZpbGUucGF0aChnc2VhX2ZvbGRlcl9uYW1lLCBzcHJpbnRmKCJnc2VhX3JlcG9ydF9mb3JfbmFfcG9zXyVzLnRzdiIsIGdzZWFfam9iX2lkKSksIHNlcCA9ICJcdCIpCmdzZWFfbmVnIDwtIHJlYWQuY3N2KGZpbGUucGF0aChnc2VhX2ZvbGRlcl9uYW1lLCBzcHJpbnRmKCJnc2VhX3JlcG9ydF9mb3JfbmFfbmVnXyVzLnRzdiIsIGdzZWFfam9iX2lkKSksIHNlcCA9ICJcdCIpCmBgYAoKV2Ugd291bGQgbGlrZSB0byBwYXJzZSB0aGUgcm93cyBpbiB0aGUgR1NFQSByZXBvcnQgc28gdGhhdCBpdCBpcyBtb3JlIHJlYWRhYmxlLgoKYGBge3IgcGFyc2VfZ3NlYV9uYW1lX2NvbH0KIyBwYXJzZSB0aGUgTkFNRSBjb2x1bW4gaW4gR1NFQSBvdXRwdXQgKHNwbGl0IGJ5ICclJykKcGFyc2VHc2VhTmFtZSA8LSBmdW5jdGlvbihnc2VhX3RhYmxlKSB7CiAgc3BsaXR0ZWRfbmFtZXMgPSByZXNoYXBlMjo6Y29sc3BsaXQoZ3NlYV90YWJsZSROQU1FLCAnJScsIG5hbWVzID0gYygiZGVzY3JpcHRpb24iLCAnc3JjJywgJ2lkJykpCiAgcmV0dXJuKGNiaW5kKGdzZWFfdGFibGUsIHNwbGl0dGVkX25hbWVzKSkKfQoKZ3NlYV9wb3MgPC0gcGFyc2VHc2VhTmFtZShnc2VhX3BvcykKZ3NlYV9uZWcgPC0gcGFyc2VHc2VhTmFtZShnc2VhX25lZykKCmthYmxlKGhlYWQoZ3NlYV9wb3NbLGMoImRlc2NyaXB0aW9uIiwgInNyYyIsICJTSVpFIiwgIk5FUyIsICJFUyIpXSksIGNhcHRpb24gPSAiVGFibGUgMjogVG9wIHRlcm1zIG9mIHVwcmVndWFsdGVkIGdlbmVzIikgJT4lIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoInN0cmlwZWQiKQoKa2FibGUoaGVhZChnc2VhX25lZ1ssYygiZGVzY3JpcHRpb24iLCAic3JjIiwgIlNJWkUiLCAiTkVTIiwgIkVTIildKSwgY2FwdGlvbiA9ICJUYWJsZSAzOiBUb3AgdGVybXMgb2YgZG93bnJlZ3VsYXRlZCBnZW5lcyIpICU+JSBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikKYGBgCldlIGFsc28gcHJlc2VudCB0aGUgZW5yaWNobWVudCBwbG90cyBmb3Igc29tZSBvZiB0aGUgdG9wIHRlcm1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMuCgoKIVtGaWd1cmUgMTogRW5yaWNobWVudCBwbG90IGZvciAiVU5GT0xERUQgUFJPVEVJTiBSRVNQT05TRSIgZnJvbSBSZWFjdG9tZV0oZW5yaWNobWVudF9wbG90X1VQUi5wbmcpCgo8YnI+CgohW0ZpZ3VyZSAyOiBFbnJpY2htZW50IHBsb3QgZm9yICJSZXNwb25zZSB0byBFUiBzdHJlc3MiIGZyb20gR09CUF0oZW5yaWNobWVudF9wbG90X0VSU3RyZXNzLnBuZykKClRoZSB0b3AgdGVybXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB1cHJlZ3VsYXRlZCBnZW5lcyBhcmUgYWxsIHJlbGF0ZWQgdG8gRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCBtb3JlIGludGVyZXN0aW5nbHksIHVuZm9sZGVkIHByb3RlaW4gcmVzcG9uc2UuIEluIHBhcnRpY3VsYXIsIEVSQUQgKEVSIGFzc29jYWl0ZWQgcHJvdGVpbiBkZWdyYWRhdGlvbikgcGF0aHdheSBpcyBhbHNvIG9uZSBvZiB0aGUgdG9wIHRlcm1zLiBUaG9zZSBwYXRod2F5cyBhbmQgbWVjaGFuaXNtcyBhcmUgYWxzbyBkaXNjdXNzZWQgaW4gdGhlIGxpdGVyYXR1cmUuIFdlIHdpbGwgZXhwbG9yZSB0aG9zZSBwYXRod2F5IHVzaW5nIG5ldHdvcmsgYW5hbHlzaXMgaW4gdGhlIG5leHQgc2VjdGlvbi4KCiMjIERpc2N1c3Npb24KCjEuIEZvciB0aGlzIGFuYWx5c2lzLCBJIHVzZWQgR1NFQSB2ZXJzaW9uIDQuMi4zLiBJIHVzZWQgdGhlIEdTRUEgcHJlcmFua2VkIGFuYWx5c2lzIGluIEdTRUEuIFRoZSBnZW5lc2V0IHVzZWQgd2FzIG9idGFpbmVkIGZyb20gQmFkZXIncyBsYWIncyByZXBvc2l0b3J5LiBUaGUgY29kZSBmb3Igb2J0YWluaW5nIHRoZSBnZW5lc2V0IGlzIHNob3duIGFib3ZlLiBUaGUgZ2VuZXNldCBpcyBjcmVhdGVkIG9uIEFwcmlsIDEsIDIwMjIuIFRoZSBnZW5lc2V0IGlzIGN1cmF0ZWQgZnJvbSBHTywgR09CUCwgTVNpZ2RiLCBSZWFjdG9tZSwgV2lraVBhdGh3YXlzLCBOZXRQYXRoLCBQYW50aGVyLCBhbmQgSHVtYW5DeWMuCgoyLiBJbiB0aGUgZW5yaWNobWVudCByZXN1bHQsIHRoZSBwb3NpdGl2ZSBwaGVub3R5cGUgYXJlIHRoZSBzYW1wbGVzIHRyZWF0ZWQgd2l0aCBDQkQsIGFuZCB0aGUgbmVnYXRpdmUgcGhlbm90eXBlIGFyZSB0aGUgb25lcyB3aXRob3V0IENCRCB0cmVhdG1lbnQuIDEwNjQgLyAyMDU5IGdlbmUgc2V0cyBhcmUgdXByZWd1bGF0ZWQgaW4gdGhlIHBvc2l0aXZlIHNhbXBsZXMsIGFuZCA5OTUgLyAyMDU5IGdlbmUgc2V0cyBhcmUgdXByZWd1bGF0ZWQgaW4gdGhlIG5lZ2F0aXZlIHNhbXBsZXMuIEluIHRoZSBwb3NpdGl2ZSBwaGVub3R5cGUsIDIxNyBnZW5lIHNldHMgYXJlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgYXQgbm9taW5hbCBwdmFsdWUgPCAxJTsgaW4gdGhlIG5lZ2F0aXZlIHBoZW5vdHlwZSwgMzQyIGdlbmUgc2V0cyBhcmUgc2lnbmlmaWNhbnRseSBlbnJpY2hlZCBhdCBub21pbmFsIHB2YWx1ZSA8IDElLiBUaGUgdG9wIHRlcm1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgcG9zaXRpdmUgc2FtcGxlcyBhcmU6IFJFU1BPTlNFIFRPIEVORE9QTEFTTUlDIFJFVElDVUxVTSBTVFJFU1MgKEdPKSwgVU5GT0xERUQgUFJPVEVJTiBSRVNQT05TRSAoVVBSKSAoUmVhY3RvbWUpLCBJUkUxQUxQSEEgQUNUSVZBVEVTIENIQVBFUk9ORVMgKFJlYWN0b21lKS4gVGhlIHRvcCB0ZXJtcyBhc3NvY2lhdGVkIHdpdGggdGhlIG5lZ2F0aXZlIHNhbXBsZXMgYXJlOiBOVUNMRUFSIENIUk9NT1NPTUUgU0VHUkVHQVRJT04sIENIUk9NT1NPTUUgU0VHUkVHQVRJT04sIFNJU1RFUiBDSFJPTUFUSUQgU0VHUkVHQVRJT04sIGFsbCBmcm9tIEdPQlAuCgozLiBUaGUgcmVzdWx0cyBmcm9tIG5vbi10aHJlc2hvbGRlZCBhbmFseXNpcyB1c2luZyBHU0VBIGlzIHZlcnkgc2ltaWxhciB0byB0aGUgcmVzdWx0IG9idGFpbmVkIGZyb20gdGhlIHByZXZpb3VzIGFuYWx5c2lzIHVzaW5nIEc6cHJvZmlsZXIuIFRoZSB1cHJlZ3VsYXRlZCBnZW5lcyBhcmUgbW9zdGx5IHJlbGF0ZWQgdG8gRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCBwcm90ZWluIGRlZ3JhZGF0aW9uIHdoZXJlYXMgdGhlIGRvbndyZWd1bGF0ZWQgZ2VuZXMgYXJlIG1vc3RseSByZWxhdGVkIHRvIGNlbGwgY3ljbGUgcmVndWxhdGlvbiBhbmQgY2VsbCBkaXZpc2lvbnMuIEhvd2V2ZXIsIG92ZXJhbGwsIHRoZSB0ZXJtcyBmcm9tIHRoZSByZXN1bHRzIHVzaW5nIEdTRUEgaXMgbW9yZSBkaXZlcnNlLiBUaGlzIGlzIGJlY2F1c2UgR1NFQSBpcyBub3QgYSB0aHJlc2hvbGRlZCBtZXRob2QgYW5kIGl0IGdldHMgdG8gY29uc2lkZXIgYWxsIGdlbmVzIGluc3RlYWQgb2YganVzdCB0aG9zZSBwYXNzZWQgdGhlIHRocmVzaG9sZCBpbiB0aHJlc2hvbGRlZCBtZXRob2RzLiBBbHRob3VnaCB0aGUgdG9wIHRlcm1zIGFyZSBtb3N0bHkgdGhlIHNhbWUsIHRoaXMgaXMgbm90IGEgc3RyYWlnaHRmb3J3YXJkIGNvbXBhcmlzb24gYmVjYXVzZSB0aGUgdHdvIG1ldGhvZHMgKEdTRUEgdi5zLiBHOnByb2ZpbGVyKSB1c2VzIGRpZmZlcmVudCBhcHByb2FjaGVzLiBUaGUgc2ltaWxhcml0eSBpbiB0aGUgdGhlIHRvcCB0ZXJtcyBpcyBsaWtlbHkgYXR0cmlidXRlZCB0byB0aGUgc2lnbmlmaWNhbnQgb3ZlcnJlcHJlc2VudGF0aW9uIG9mIGNlcnRhaW4gZ2VuZXMuIFRoaXMgYWxzbyBnaXZlcyB1cyBzdHJvbmcgZXZpZGVuY2UgdG8gYmVsaWV2ZSB0aGF0IHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgYXJlIG1vcmUgbGlrZWx5IHRoYW4gbm90IHRvIGJlIGludm9sdmVkIGluIHRoZXNlIHBhdGh3YXlzLgoKIyBOZXR3b3JrIEFuYWx5c2lzIFVzaW5nIEN5dG9zY2FwZQoKIyMgQ3JlYXRpb24gb2YgRW5yaWNobWVudCBNYXAKCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBpbXBvcnQgdGhlIHJlc3VsdHMgZnJvbSBHU0VBIGludG8gQ3l0b3NjYXBlIGFuZCB2aXN1YWxpemUgdGhlIGVucmljaG1lbnQgcmVzdWx0cyBhcyBhIG5ldHdvcmsuIFRvIHRoaXMgZW5kLCB3ZSBmaXJzdCBuZWVkIHRvIGNyZWF0ZSBhIG5ldHdvcmsgYmFzZWQgb24gdGhlIGVucmljaG1lbnQgcmVzdWx0LiBXZSB1c2UgdGhlIEN5dG9zY2FwZSBwbHVnaW4gRW5yaWNobWVudE1hcCwgd2hpY2ggY2FuIGdlbmVyYXRlIGEgbmV0d29yayBmcm9tIEdTRUEgb3V0cHV0cy4KCldlIGNyZWF0ZWQgdGhlIGVucmljaG1lbnQgbWFwIGJ5IHVzaW5nIHRoZSBDeXRvc2NhcGUgR1VJLiBXZSBmaXJzdCBpbXBvcnRlZCB0aGUgR1NFQSBvdXRwdXQgZm9yIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSBwaGVub3R5cGVzLiBUaGVuLCB3ZSBpbXBvcnRlZCB0aGUgR01UIGZpbGUgYW5kIHJhbmtlZCBsaXN0IGZpbGUuIEZpbmFsbHksIHdlIGluc3BlY3RlZCBhbmQgY2hhbmdlZCB0aGUgcGFyYW1ldGVycyBmb3IgRW5yaWNobWVudCBtYXAuIFRoZSB0aHJlc2hvbGRzIGZvciBFbnJpY2htZW50TWFwIGFyZSBhcyBmb2xsb3dzOgoKLSBGRFIgcS12YWx1ZSBjdXRvZmY6IDAuMQotIHAtdmFsdWUgY3V0b2ZmOiAwLjA1Ci0gRWRnZSBjdXRvZmY6IDAuMzc1Ci0gRWRnZSBmaWx0ZXJpbmcgbWV0cmljOiBKYWNjYXJkK092ZXJsYXAgY29tYmluZWQKLSBQYXJzZSBiYWRlcmxhYiBuYW1lcyBpbiBHTVQgZmlsZTogVHJ1ZSAoZm9yIGJldHRlciByZWFkYWJpbGl0eSkKClJlY2FsbCB0aGF0IEphY2NhcmQgbWV0cmljIG1lYXN1cmVzIHRoZSBpbnRlcnNlY3Rpb24gb3ZlciB1bmlvbiB3aGVyZWFzIHRoZSBvdmVybGFwIG1ldHJpYyBtZWFzdXJlcyBpbnRlcnNlY3Rpb24gb3ZlciB0aGUgbWluaW11bSBzaXplLgoKVGhlIHJlc3VsdGluZyBuZXR3b3JrIGlzIHNob3duIGJlbG93OgoKIVtGaWd1cmUgMzogRW5yaWNobWVudCBtYXAgZ2VuZXJhdGVkIGZyb20gR1NFQSByZXN1bHQuIFBvc2l0aXZlIHBoZW5vdHlwZXMgKHVwcmVndWxhdGVkKSBhcmUgY29sb3JlZCByZWQgYW5kIG5lZ2F0aXZlIHBoZW5vdHlwZXMgKGRvd25yZWd1bGF0ZWQpIGFyZSBjb2xvcmVkIGJsdWUuXShhM2ZpZ3MvY3l0b3NjYXBlL25ldHdvcmtfb3ZlcnZpZXcucG5nKQoKQSB6b29tZWQgaW4gdmlldyBvZiB0aGUgY2x1c3RlciBvZiB0ZXJtcyBhc3NvY2lhdGVkIHdpdGggRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCB1bmZvbGRlZCBwcm90ZWluIHJlc3BvbnNlLiBUaGVzZSBhcmUgdGhlIGNsdXN0ZXJzIHRoYXQgd2Ugd2lsbCBmdXJ0aGVyIGludmVzdGlnYXRlLgoKIVtGaWd1cmUgNDogQSB6b29tZWQgaW4gdmlldyBvZiB0aGUgZW5yaWNobWVudCBtYXAgc2hvd2luZyB0aGUgY2x1c3RlciBjb250YWluaW5nIHRlcm1zIGFuZCBwYXRod2F5cyB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCB1bmZvbGRlZCBwcm90ZWluIHJlc3BvbnNlLiBUaG9zZSBhcmUgdGhlIHBhdGh3YXlzIHRoZSBhdXRob3JzIG9mIHRoZSBvcmlnaW5hbCBwYXBlciBwcm9wb3NlZCB0byBiZSByZWxhdGVkIHRvIENCRCdzIHJvbGUgaW4gaW5oaWJpdGluZyBTQVJTLUNvVi0yIHJlcGxpY2F0aW9uLl0oYTNmaWdzL2N5dG9zY2FwZS9uZXR3b3JrX3pvb21pbi5wbmcpCgohW0ZpZ3VyZSA1OiBBIHpvb21lZCBpbiB2aWV3IG9mIHRoZSBlbnJpY2htZW50IG1hcCBzaG93aW5nIHRoZSBjbHVzdGVyIGNvbnRhaW5pbmcgdGVybXMgYW5kIHBhdGh3YXlzIHRoYXQgYXJlIGFzc29jaWF0ZWQgd2l0aCBpbnRlcmZlcm9uIHJlc3BvbnNlcy4gVGhlIGF1dGhvcnMgb2YgdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uIG1lbnRpb25lZCB0aGF0IHRoZXNlIHBhdGh3YXlzIGFzIGFuIGFsdGVybmF0aXZlIG1lY2hhbmlzbSBvZiBDQkQncyBpbmhpYml0aW9uIG9mIFNBUlMtQ29WLTIgcmVwbGljYXRpb24uIF0oYTNmaWdzL2N5dG9zY2FwZS9uZXR3b3JrX2ludGVyZmVyb25fem9vbWluLnBuZykKCiMjIE5ldHdvcmsgQW5ub3RhdGlvbgoKTmV4dCwgd2UgYW5ub3RhdGVkIHRoZSBuZXR3b3JrIHVzaW5nIHRoZSBwbHVnaW4gQXV0b0Fubm90YXRlLiBGb3IgQXV0b0Fubm9hdGUsIHdlIHVzZWQgdGhlIGRlZmF1bHQgcGFyYW1ldGVyOgotIExhYmVsaW5nIGFsZ29yaXRobTogV29yZENsb3VkIEFkamFjZW50IFdvcmQKLSBNYXggd29yZCBwZXIgbGFiZWw6IDMKLSBNaW4gd29yZCBvY2N1cnJlbmNlOiAxCi0gQWRqYWNlbnQgd29yZCBib251czogOAoKQWRkaXRpb25hbGx5LCB3ZSB0dXJuZWQgb24gdGhlIG9wdGlvbiAiTGF5b3V0IG5ldHdvcmsgdG8gcHJldmVudCBjbHVzdGVyIG92ZXJsYXAiIHNvIHRoYXQgdGhlIHJlc3VsdGluZyBhbm5vdGF0ZWQgbmV0d29yayBpcyBtb3JlIGNsZWFyIGFuZCBlYXN5LXRvLXJlYWQuCgpUaGUgcmVzdWx0aW5nIGFubm90YXRlZCBuZXR3b3JrIGlzIHNob3duIGJlbG93LgoKIVtGaWd1cmUgNjogQW5ub3RhdGVkIG5ldHdvcmsgb2YgdGhlIG9yaWdpbmFsIG5ldHdvcmsgc2hvd24gaW4gRmlndXJlIDUuIENsdXN0ZXJzIGFyZSByZS1sYXlvdXQgdG8gcHJldmVudCBvdmVybGFwIGFuZCBpbXByb3ZlIHJlYWRhYmlsaXR5Ll0oYTNmaWdzL2N5dG9zY2FwZS9uZXR3b3JrX2Fubm90YXRlZC5wbmcpCgojIyBTdW1tYXJ5IE5ldHdvcmsKCldlIGNvbGxhcHNlZCB0aGUgYW5ub3RhdGVkIG5ldHdvcmsgaW50byBhIHN1bW1hcnkgbmV0d29yayB1c2luZyB0aGUgYnVpbHQtaW4gZmVhdHVyZSBwcm92aWRlZCBieSBBdXRvQW5ub3RhdGUuCgohW0ZpZ3VyZSA3OiBTdW1tYXJ5IG5ldHdvcmsgd2l0aCB0aGUgYW5ub3RhdGlvbiBjbHVzdGVycyBjb2xsYXBzZWQuXShhM2ZpZ3MvY3l0b3NjYXBlL1N1bW1hcnlOZXR3b3JrLnBuZykKCiFbRmlndXJlIDg6IEEgem9vbWVkIGluIHZpZXcgb2YgdGhlIGNlbnRlciBvZiB0aGUgc3VtbWFyeSBuZXR3b3JrLiBUaGUgaGlnaGxpZ2h0ZWQgbm9kZXMgcmVwcmVzZW50IHRoZSBtYWluIHRoZW1lIG9mIHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuXShhM2ZpZ3MvY3l0b3NjYXBlL3N1bW1hcnlfbmV0X3pvb21pbi5wbmcpCgpUaGUgbWFqb3IgdGhlbWVzIGluIHRoZSBhbmFseXNpcyBhcmU6CgotIEVSIHN0cmVzcyAodXByZWd1bGF0ZWQpCi0gUHJvdGVpbiBkZWdyYWRhdGlvbiAodXByZWd1bGF0ZWQpCi0gSW1tdW5lIHJlc3BvbnNlICh1cHJlZ3VsYXRlZCkKLSBQcm90ZWluIGZvbGRpbmcgKHVwcmVndWxhdGVkKQotIENlbGwgY3ljbGUgKGRvd25yZWd1bGF0ZWQpCi0gRE5BIHJlcGFpciAoZG93bnJlZ3VsYXRlZCkKClRoZSB1cHJlZ3VsYXRlZCBwYXRod2F5cyBmaXQgdGhlIG1vZGVsIGFuZCBhZ3JlZSB3aXRoIHRoZSByZXN1bHRzIGJ5IHRoZSBhdXRob3JzIG9mIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gVGhlIGF1dGhvcnMgZGlkIG5vdCBtZW50aW9uIHRvbyBtdWNoIGFib3V0IHRoZSBuZWdhdGl2ZWx5IHJlZ3VsYXRlZCBwYXRod2F5cy4gVGhleSBhcmUgbm90IG5lY2Vzc2FyaWx5IG5vdmVsIGJ1dCBub25ldGhlbGVzcyB3b3J0aCBmdXRoZXIgaW52ZXN0aWdhdGluZy4KCiMjIERpc2N1c3Npb24KCkRpc2N1c3Npb24gcXVlc3Rpb25lZCBhbnN3ZXJlZCBpbiB0aGUgcHJldmlvdXMgc3Vic2VjdGlvbnMuCgojIyBQdWJsaWNhdGlvbi1yZWFkeSBGaWd1cmUKCgoKIVtGaWd1cmUgOTogUHVibGljYXRpb24tcmVhZHkgZmlndXJlLiAoYSkgVGhlIGVudGlyZSBlbnJpY2htZW50IG1hcCwgZ2VuZXJhdGVkIHVzaW5nIHRoZSBFbnJpY2htZW50TWFwIHBsdWdpbiBpbiBDeXRvc2NhcGU7IChiKSBBIHpvb21lZC1pbiB2aWV3IG9mIHRoZSBlbnJpY2htZW50IG1hcCBzaG93aW5nIHBhdGh3YXlzIHJlbGF0aW5nIHRvIEVSIHN0cmVzcyByZXNwb25zZSBhbmQgdW5mb2xkZWQgcHJvdGVpbiByZXNwb25zZTsgKGMpIEEgY29sbGFwc2VkIHN1bW1hcnkgbmV0d29yazsgKGQpIEEgem9vbWVkLWluIHZpZXcgb2YgdGhlIHN1bW1hcnkgbmV0d29yayBoaWdobGlnaHRpbmcgdGhlIG1ham9yIHRoZW1lcy5dKGEzZmlncy9jeXRvc2NhcGUvbmV0d29ya19wdWJsaWNfZmlnLnBuZykKCihVbmZvcnR1bmF0ZWx5LCByZXNvbHV0aW9uIG9mIGZpZ3VyZXMgaXMgYSBsaXR0bGUgYml0IGxvdyBhbmQgdGhlIERQSSBvcHRpb24gZG9lcyBub3Qgc2VlbSB0byB3b3JrLiBQbGVhc2UgcmVmZXIgdG8gam91cm5hbCBmb3IgaGlnaGVyIHJlc29sdXRpb24gZmlndXJlcy4pCgojIEZpbmFsIERpc2N1c3Npb24KCjEuIFRoZSBlbnJpY2htZW50IHJlc3VsdHMgc3VwcG9yIHRoZSBjb25jbHVzaW9ucyBhbmQgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXIuIFRoZSByZXN1bHRzIGRvIG5vdCBkaWZmZXIgc2lnbmlmaWNhbnRseSBmcm9tIHRob3NlIGZyb20gQXNzaWdubWVudCAyLgoKMi4gVGhlIGludm9sdmVtZW50IG9mIHRoZSBnZW5lcyBpbiBFUiBzdHJlc3MgcmVzcG9uc2UgYW5kIHRoZSBtZWNoYW5pc20gb2YgdW5mb2xkZWQgcHJvdGVpbiByZXNwb25zZSBwYXRod2F5IGFyZSBkaXNjdXNzZWQgZXh0ZW5zaXZlbHkgaW4gKDIwMDgpIEVpemlyaWsgZXQgYWwuIGFuZCAoMjAwNSkgQ3JlZGxlIGV0IGFsLiBUaGUgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGVzZSBwYXBlcnMgYWxzbyBhZ3JlZSB3aXRoIHRoZSBwcm9wb3NlZCBtZWNoYW5pc20gb2YgQ0JEJ3MgYW50aXZpcmFsIGVmZmVjdCBkaXNjdXNzZWQgYnkgaW4gdGhlIG9yaWdpbmFsIHBhcGVyIGFuZCB0aGUgcmVzdWx0cyBvYnRhaW5lZCBpbiB0aGlzIGFuYWx5c2lzLgoKIyBBbmFseXNpcyBvZiBVUFIgUGF0aHdheQoKV2UgZnVydGhlciBpbnZlc3RpZ2F0ZSB0aGUgdW5mb2xkZWQgcHJvdGVpbiByZXNwb25zZSBwYXRod2F5LiBUaGUgcGF0aHdheSBpcyBvZiBwYXJ0aWN1bGFyIGludGVyZXN0IGJlY2F1c2UgdGhlIGF1dGhvcnMgcHJvcG9zZWQgdGhpcyBhcyB0aGUgcG90ZW50aWFsIG1lY2hhbmlzbSBmb3IgdGhlIGFudGl2aXJhbCBlZmZlY3Qgb2YgQ0JELiBUaGlzIHBhdGh3YXkgaXMgYXZhaWxhYmxlIG9uIFJlYWN0b21lLiBIZXJlIGlzIGEgZGV0YWlsZWQgcGF0aHdheSBkaWFncmFtIG9idGFpbmVkIGZyb20gUmVhY3RvbWUuCgohW0ZpZ3VyZSAxMDogUGF0aHdheSBkaWFncmFtIGZvciB0aGUgVW5mb2xkZWQgUHJvdGVpbiBSZXNwb25zZSBwYXRod2F5Ll0oYTNmaWdzL1VQUi5wbmcpCgpFeHBvcnQgdGhlIG5vcm1hbGl6ZWQgY291bnQgZmlsZSAod2l0aCBIR05DIHN5bWJvbCBhbm5vdGF0aW9uKSBmb3IgYW5ub3RhdGlvbiBvbiBSZWFjdG9tZSBwYXRod2F5IGRpYWdyYW0uCgpgYGB7ciBleHBvcnRfbm9ybWFsaXplZF9jb3VudF9hbm5vdGF0ZWR9CndyaXRlLmNzdihub3JtYWxpemVkX2NvdW50c19hbm5vdFszOjE0XSwgZmlsZSA9ICJub3JtYWxpemVkX2NvdW50X2Fubm90YXRlZC50eHQiKQp3cml0ZS5jc3YocWxmX2RpZmZfZXhwJHRhYmxlLCBmaWxlID0gInFsZl9kaWZmX2V4cC50eHQiKQpgYGAKClRoZSBleHByZXNzaW9uIGRhdGEgaXMgdXBsb2FkZWQgdG8gdGhlIG9ubGluZSBhbmFseXNpcyB0b29scyBwcm92aWRlZCBieSBSZWFjdG9tZS4gQmVsb3cgaXMgdGhlIHJlc3VsdGluZyBwYXRod2F5IGRpYWdyYW0gd2l0aCB0aGUgZ2VuZXMgaW4gdGhlIHBhdGh3YXkgY29sb3JlZCBiYXNlZCBvbiB0aGVpciBsZXZlbCBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiAobG9nIEZDKS4gQXMgc2hvd24gaW4gdGhlIGZpZ3VyZSwgdGhlIG1ham9yaXR5IG9mIGdlbmVzIGluIHRoaXMgcGF0aHdheSBhcmUgdXByZWd1bGF0ZWQgYWx0aG91Z2ggYSBoYW5kZnVsIGFyZSBhbHNvIGRvd25yZWd1bGF0ZWQuIFVuZm9ydHVuYXRlbHksIHRoZSBidWlsdC1pbiB0b29sIGluIFJlYWN0b21lIGRvZXMgbm90IGFsbG93IHVzIHRvIGFubm90YXRlIHRoZSBwYXRod2F5IHdpdGggcC12YWx1ZSBvciB0aGUgYWN1dGFsIG51bWVyaWFsIGxvZ0ZDIHZhbHVlLgoKIVtGaWd1cmUgMTE6IFBhdGh3YXkgZGlhZ3JhbSBmb3IgdGhlIFVuZm9sZGVkIFByb3RlaW4gUmVzcG9uc2UgcGF0aHdheSB3aXRoIGdlbmVzIGluIHRoZSBwYXRod2F5IGNvbG9yLWNvZGVkIHRvIHJlZmxlY3QgdGhlIGxvZyBmb2xkIGNoYW5nZS5dKGEzZmlncy9VUFItY29sb3ItY29kZWQucG5nKQoKV2UgcmVwZWF0IGEgc2ltaWxhciBhbmFseXNpcyB1c2luZyBDeXRvc2NhcGUuIFRoaXMgdGltZSwgd2UgdXNlIHRoZSBleHByZXNzaW9uIGRhdGEgb2J0YWluZWQgaW4gQTIuIFRoaXMgZmlsZSBpbmNsdWRlcyBub3Qgb25seSB0aGUgbG9nRkMgYnV0IGFsc28gdGhlIHAtdmFsdWVzIGZvciBlYWNoIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lLiBBZnRlciBpbXBvcnRpbmcgdGhlIFJlYWN0b21lIHBhdGh3YXkgaW50byBDeXRvc2NhcGUsIHdlIHdyaXRlIGFuIGF1dG9tYXRpb24gc2NyaXB0IHRvIGFubm90YXRlIHRoZSBuZXR3b3JrIHVzaW5nIGxvZ0ZDIGFuZCBwLXZhbHVlczoKCmBgYHtyIHJlYWN0b21lX2Fubm90YXRlLCBldmFsPUZBTFNFfQpub2RlcyA8LSBSQ3kzOjpnZXRBbGxOb2RlcygpCmF0dHJpYl90YWJsZSA8LSBSQ3kzOjpnZXRUYWJsZUNvbHVtbnMoKQpmb3IgKG4gaW4gbm9kZXMpIHsKICBucG9zID0gUkN5Mzo6Z2V0Tm9kZVBvc2l0aW9uKG5vZGUubmFtZXMgPSBuKQogIGF0dHJpYiA9IGF0dHJpYl90YWJsZVthdHRyaWJfdGFibGUkbmFtZSA9PSBuLF0KICBpZiAoIWlzLm51bGwoYXR0cmliJGxvZ0ZDKSkgewogICAgUkN5Mzo6YWRkQW5ub3RhdGlvblRleHQodGV4dCA9IHNwcmludGYoImxvZ0ZDID0gJS4yZiIsIGF0dHJpYiRsb2dGQyksIHgucG9zID0gbnBvcyR4X2xvY2F0aW9uLCB5LnBvcyA9IG5wb3MkeV9sb2NhdGlvbikKICAgIFJDeTM6OmFkZEFubm90YXRpb25UZXh0KHRleHQgPSBzcHJpbnRmKCJwID0gJS4yZyIsIGF0dHJpYiRQVmFsdWUpLCB4LnBvcyA9IG5wb3MkeF9sb2NhdGlvbiwgeS5wb3MgPSBucG9zJHlfbG9jYXRpb24gKyAxMikKICB9Cn0KCmBgYAoKVGhpcyBzY3JpcHQgd2FzIHJ1biBvdXRzaWRlIHRoZSBub3RlYm9vay4gSXQgaXMgc2hvd24gaGVyZSBmb3IgZGVtb25zdHJhdGlvbiBwdXJwb3NlIG9ubHkuCgpUaGUgZmluYWwgYW5ub2F0ZWQgbmV0d29yayBpcyBhbm5vdGVkIHdpdGggbG9nRkMgYW5kIHAtdmFsdWVzLiBUaGUgY29sb3Igb2YgZWFjaCBub2RlIGNvcnJlc3BvbmRzIHRvIGxvZyBmb2xkIGNoYW5nZSAocmVkID0gdXByZWd1bGF0ZWQsIGJsdWUgPSBkb3ducmVndWxhdGVkKSBhbmQgdGhlIHNpemUgb2YgZWFjaCBub2RlIGlzIGludmVyc2UgcHJvcG9ydGlvbmFsIHRvIHRoZSBwLXZhbHVlIG9mIHRoZSBnZW5lIHJlcHJlc2VudGVkIGJ5IHRoZSBub2RlLgoKIVtGaWd1cmUgMTI6IEFubm90YXRlZCByZWFjdG9tZSBwYXRod2F5LiBUaGUgbGFyZ2VyIGEgbm9kZSwgdGhlIGxvd2VyIHRoZSBwLXZhbHVlLiBSZWQgY29ycmVzcG9uZHMgdG8gYSBoaWdoIGxvZ0ZDIHZhbHVlICh1cHJlZ3VsYXRlZCkgd2hlcmVhcyBibHVlIGNvcnJlc3BvbmRzIHRvIGEgbG93IChuZWdhdGl2ZSkgbG9nRkMgdmFsdWUgKGRvd25yZWd1bGF0ZWQpLl0oYTNmaWdzL2N5dG9zY2FwZS9yZWFjdG9tZV9hbm5vdGF0ZWQucG5nKQoKQXMgc2hvd24gaW4gdGhlIGZpZ3VyZSBhYm92ZSwgd2UgY2FuIHNlZSB0aGUgZ2VuZXMgaW52b2x2ZWQgaW4gdGhlIHVuZm9sZGVkIHByb3RlaW4gcmVzcG9uc2UgcGF0aHdheSBhcmUgbW9zdGx5IHNpZ25pZmljYW50bHkgdXByZWd1bGF0ZWQuIFRoaXMgaXMgY29uc2lzdGVudCB3aXRoIHRoZSBmaW5kaW5nIGluIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gVGhlIGF1dGhvcnMgZnVydGhlciBjb25maXJtZWQgdGhpcyBieSBvYnNlcnZpbmcgdGhlIGVmZmVjdCBvbiBTQVJTLUNvVi0yIGluZmVjdGlvbiBpbiBjZWxscyB3aXRoIHRoZSBFUk4xIGdlbmUgKG9uZSBvZiB0aGUgZ2VuZSBpbnZvbHZlZCBpbiB0aGlzIHBhdGh3YXkpIGtub2NrZWQgb3V0LiBUaGVpciBleHBlcmltZW50IHNob3dzIHJlZHVjZWQgYW50aXZpcmFsIGVmZmVjdHMgZXZlbiB3aXRoIENCRCB0cmVhdG1lbnQgaW4gRVJOMSBrbm9ja291dCBjZWxscy4KCiMgSm91cm5hbAoKTGluayB0byBteSBqb3VybmFsIGVudHJ5IGZvciB0aGlzIGFzc2lnbm1lbnQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9iY2I0MjAtMjAyMi9LZXZpbl9HYW8vd2lraS9Bc3NpZ25tZW50LTMKCiMgUmVmZXJlbmNlCgpJc3NlcmxpbiwgUi4gKG4uZC4pLiBFbnJpY2htZW50IE1hcCBBbmFseXNpcyBQaXBlbGluZS4gQmFkZXIgTGFiIEdpdEh1Yi4KCkt1Y2VyYSwgTS4sIElzc2VybGluLCBSLiwgQXJraGFuZ29yb2Rza3ksIEEuLCAmIEJhZGVyLCBHLiBELiAoMjAxNikuIEF1dG9Bbm5vdGF0ZTogQSBDeXRvc2NhcGUgYXBwIGZvciBzdW1tYXJpemluZyBuZXR3b3JrcyB3aXRoIFNlbWFudGljIEFubm90YXRpb25zLiBGMTAwMFJlc2VhcmNoLCA1LCAxNzE3LiBodHRwczovL2RvaS5vcmcvMTAuMTI2ODgvZjEwMDByZXNlYXJjaC45MDkwLjEKCgpSZWltYW5kLCBKLiwgSXNzZXJsaW4sIFIuLCBWb2lzaW4sIFYuLCBLdWNlcmEsIE0uLCBUYW5udXMtTG9wZXMsIEMuLCBSb3N0YW1pYW5mYXIsIEEuLCBXYWRpLCBMLiwgTWV5ZXIsIE0uLCBXb25nLCBKLiwgWHUsIEMuLCBNZXJpY28sIEQuLCAmIEJhZGVyLCBHLiBELiAoMjAxOSkuIFBhdGh3YXkgZW5yaWNobWVudCBhbmFseXNpcyBhbmQgdmlzdWFsaXphdGlvbiBvZiBPTUlDUyBkYXRhIHVzaW5nIEc6UHJvZmlsZXIsIEdTRUEsIEN5dG9zY2FwZSBhbmQgRW5yaWNobWVudE1hcC4gTmF0dXJlIFByb3RvY29scywgMTQoMiksIDQ4MuKAkzUxNy4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTk2LTAxOC0wMTAzLTkKCkNoZW4gWSwgTHVuIEFUTCwgU215dGggR0sgKDIwMTYpLiBGcm9tIHJlYWRzIHRvIGdlbmVzIHRvIHBhdGh3YXlzOiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBvZiBSTkEtU2VxIGV4cGVyaW1lbnRzIHVzaW5nIFJzdWJyZWFkIGFuZCB0aGUgZWRnZVIgcXVhc2ktbGlrZWxpaG9vZCBwaXBlbGluZS4gRjEwMDBSZXNlYXJjaCA1LCAxNDM4CgpEdXJpbmNrLCBTLiwgU3BlbGxtYW4sIFAuIFQuLCBCaXJuZXksIEUuLCAmIEh1YmVyLCBXLiAoMjAwOSkuIE1hcHBpbmcgaWRlbnRpZmllcnMgZm9yIHRoZSBpbnRlZ3JhdGlvbiBvZiBnZW5vbWljIGRhdGFzZXRzIHdpdGggdGhlIFIvQmlvY29uZHVjdG9yIHBhY2thZ2UgYmlvbWFSdC4gTmF0dXJlIC0gcHJvdG9jb2xzLCA0KDgpLCAxMTg04oCTMTE5MS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbnByb3QuMjAwOS45NwpNYXJ0aW4gTW9yZ2FuICgyMDIxKS4gQmlvY01hbmFnZXI6IEFjY2VzcyB0aGUgQmlvY29uZHVjdG9yIFByb2plY3QgUGFja2FnZSBSZXBvc2l0b3J5LiBSIHBhY2thZ2UgdmVyc2lvbiAxLjMwLjE2LiBodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPUJpb2NNYW5hZ2VyCgpNY0NhcnRoeSBESiwgQ2hlbiBZIGFuZCBTbXl0aCBHSyAoMjAxMikuIERpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIG9mIG11bHRpZmFjdG9yIFJOQS1TZXEgZXhwZXJpbWVudHMgd2l0aCByZXNwZWN0IHRvIGJpb2xvZ2ljYWwgdmFyaWF0aW9uLiBOdWNsZWljIEFjaWRzIFJlc2VhcmNoIDQwLCA0Mjg4LTQyOTcKCk5ndXllbiwgTC4gQy4sIFlhbmcsIEQuLCBOaWNvbGFlc2N1LCBWLiwgQmVzdCwgVC4gSi4sIE9odHN1a2ksIFQuLCBDaGVuLCBTLi1OLiwgRnJpZXNlbiwgSi4gQi4sIERyYXltYW4sIE4uLCBNb2hhbWVkLCBBLiwgRGFubiwgQy4sIFNpbHZhLCBELiwgR3VsYSwgSC4sIEpvbmVzLCBLLiBBLiwgTWlsbGlzLCBKLiBNLiwgRGlja2luc29uLCBCLiBDLiwgVGF5LCBTLiwgT2FrZXMsIFMuIEEuLCBQYXVsaSwgRy4gRi4sIE1lbHR6ZXIsIEQuIE8uLCDigKYgUm9zbmVyLCBNLiBSLiAoMjAyMSkuIENhbm5hYmlkaW9sIGluaGliaXRzIFNBUlMtQ09WLTIgcmVwbGljYXRpb24gYW5kIHByb21vdGVzIHRoZSBob3N0IGlubmF0ZSBpbW11bmUgcmVzcG9uc2UuIFNjaWVuY2UgQWR2YW5jZXMuIGh0dHBzOi8vd3d3LnNjaWVuY2Uub3JnL2RvaS9hYnMvMTAuMTEyNi9zY2lhZHYuYWJpNjExMApSb2JpbnNvbiBNRCwgTWNDYXJ0aHkgREogYW5kIFNteXRoIEdLICgyMDEwKS4gZWRnZVI6IGEgQmlvY29uZHVjdG9yIHBhY2thZ2UgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIG9mIGRpZ2l0YWwgZ2VuZSBleHByZXNzaW9uIGRhdGEuIEJpb2luZm9ybWF0aWNzIDI2LCAxMzktMTQwCgpHdSwgWi4gKDIwMTYpIENvbXBsZXggaGVhdG1hcHMgcmV2ZWFsIHBhdHRlcm5zIGFuZCBjb3JyZWxhdGlvbnMgaW4gbXVsdGlkaW1lbnNpb25hbCBnZW5vbWljIGRhdGEuIEJpb2luZm9ybWF0aWNzLgoKS29sYmVyZyBMLCBSYXVkdmVyZSBVLCBLdXptaW4gSSwgVmlsbyBKLCBQZXRlcnNvbiBIICgyMDIwKS4g4oCcZ3Byb2ZpbGVyMi0gYW4gUiBwYWNrYWdlIGZvciBnZW5lIGxpc3QgZnVuY3Rpb25hbCBlbnJpY2htZW50IGFuYWx5c2lzIGFuZCBuYW1lc3BhY2UgY29udmVyc2lvbiB0b29sc2V0IGc6UHJvZmlsZXIu4oCdIEYxMDAwUmVzZWFyY2gsIDkgKEVMSVhJUikoNzA5KS4gUiBwYWNrYWdlIHZlcnNpb24gMC4yLjEuCgpTdGVmYW4gTWlsdG9uIEJhY2hlIGFuZCBIYWRsZXkgV2lja2hhbSAoMjAyMCkuIG1hZ3JpdHRyOiBBIEZvcndhcmQtUGlwZSBPcGVyYXRvciBmb3IgUi4gaHR0cHM6Ly9tYWdyaXR0ci50aWR5dmVyc2Uub3JnLCBodHRwczovL2dpdGh1Yi5jb20vdGlkeXZlcnNlL21hZ3JpdHRyLgp2YW4gQnJlZW1lbiwgUi4gQi4sIE11Y2hpcmksIFIuIE4uLCBCYXRlcywgVC4gQS4sIFdlaW5zdGVpbiwgSi4gQi4sIExlaWVyLCBILiBDLiwgRmFybGV5LCBTLiwgJiBUYWZlc3NlLCBGLiBHLiAoMjAyMikuIAoKQ2FubmFiaW5vaWRzIEJsb2NrIENlbGx1bGFyIEVudHJ5IG9mIFNBUlMtQ29WLTIgYW5kIHRoZSBFbWVyZ2luZyBWYXJpYW50cy4gSm91cm5hbCBvZiBuYXR1cmFsIHByb2R1Y3RzLCA4NSgxKSwgMTc24oCTMTg0LiBodHRwczovL2RvaS5vcmcvMTAuMTAyMS9hY3Muam5hdHByb2QuMWMwMDk0NgoKRmFicmVnYXQgQSwgU2lkaXJvcG91bG9zIEssIFZpdGVyaSBHLCBNYXJpbi1HYXJjaWEgUCwgUGluZyBQLCBTdGVpbiBMLCBEJ0V1c3RhY2hpbyBQLCBIZXJtamFrb2IgSC4gUmVhY3RvbWUgZGlhZ3JhbSB2aWV3ZXI6IGRhdGEgc3RydWN0dXJlcyBhbmQgc3RyYXRlZ2llcyB0byBib29zdCBwZXJmb3JtYW5jZS4gQmlvaW5mb3JtYXRpY3MgKE94Zm9yZCwgRW5nbGFuZCkuIDIwMTggQXByOzM0KDcpIDEyMDgtMTIxNC4gZG9pOiAxMC4xMDkzL2Jpb2luZm9ybWF0aWNzL2J0eDc1Mi4gUHViTWVkIFBNSUQ6IDI5MTg2MzUxLiBQdWJNZWQgQ2VudHJhbCBQTUNJRDogUE1DNjAzMDgyNi4KCkVpemlyaWssIEQuIEwuLCBDYXJkb3pvLCBBLiBLLiwgJiBDbm9wLCBNLiAoMjAwOCkuIFRoZSByb2xlIGZvciBlbmRvcGxhc21pYyByZXRpY3VsdW0gc3RyZXNzIGluIGRpYWJldGVzIG1lbGxpdHVzLiBFbmRvY3JpbmUgcmV2aWV3cywgMjkoMSksIDQy4oCTNjEuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMjEwL2VyLjIwMDctMDAxNQoKQ3JlZGxlLCBKLiBKLiwgRmluZXItTW9vcmUsIEouIFMuLCBQYXBhLCBGLiBSLiwgU3Ryb3VkLCBSLiBNLiwgJiBXYWx0ZXIsIFAuICgyMDA1KS4gT24gdGhlIG1lY2hhbmlzbSBvZiBzZW5zaW5nIHVuZm9sZGVkIHByb3RlaW4gaW4gdGhlIGVuZG9wbGFzbWljIHJldGljdWx1bS4gUHJvY2VlZGluZ3Mgb2YgdGhlIE5hdGlvbmFsIEFjYWRlbXkgb2YgU2NpZW5jZXMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSwgMTAyKDUyKSwgMTg3NzPigJMxODc4NC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwNzMvcG5hcy4wNTA5NDg3MTAyCg==